Technical Q&A QA1247
Viewing multi-page PDF files


Q: QuickTime 6 のグラフィックスインポータを使って複数ページの PDF ファイルを閲覧しようとしています。1 ページ目は閲覧できますが、GraphicsImporterGetImageCount API は、複数ページの文書でも、ページ(イメージ)番号として常に 1 を返します。すべてのページを閲覧するには、どうしたらよいのでしょうか?

A: PDF グラフィックスインポータは、複数ページの PDF ファイルの 1 ページ目しか表示しません。しかし、PDF ムービーインポータは、どのページでも表示できます。下記のコードリストは、PDF ムービーインポータを使って複数ページの PDF の各ページを描画する方法を示しています。単にムービーとしてファイルを開き、ムービー中の各フレーム(ページ)を閲覧しています。

これと同じテクニックを、アニメーション GIF などの他のファイル形式にも使用できます。詳細については、TN2018 を参照してください。



リスト 1. 複数ページの PDF ファイル の各ページの描画

#include <QuickTime/QuickTime.h>

//////////
//
// drawMultiPagePDF
//
// 複数ページある PDF 文書ファイルをムービーとして開き、
// 各ページを走査して指定されたポートに描画
//
//
//////////

void drawMultiPagePDFtoPort(FSSpec *pdfFileSpec, CGrafPtr thePort)
{
    OSErr   err = noErr;
    Movie   theMovie = nil;
    short   movieFileRefNum = 0;
    Track   firstVideoTrack = nil;

    // PDF ファイルを開く
    err = OpenMovieFile(pdfFileSpec, &movieFileRefNum, fsRdPerm);
    if (err) goto bail;
    
    // ファイルからムービーを作成
    err = NewMovieFromFile(&theMovie,
                           movieFileRefNum,
                           NULL,
                           NULL,
                           newMovieActive,
                           NULL);
    if (err) goto bail;

    // ムービーを描画するポートを設定
    SetMovieGWorld(theMovie,thePort,nil);
    if (GetMoviesError()) goto bail;
    
    // ムービーの第 1 ビデオトラックを取得
    firstVideoTrack = GetMovieIndTrackType(theMovie,
                                           1,
                                           VideoMediaType,
                                           movieTrackMediaType);
    if (firstVideoTrack)
    {
        long frameCount  = 0;

        // ビデオトラックのフレーム数を取得
        frameCount = getFrameCount (firstVideoTrack);
        for ( ; frameCount > 0; frameCount--)
        {
            // ポートにフレーム(PDF ページ)を描画
            drawMovieFrameNextOrPrev (theMovie, fixed1);
        }
    }

bail:
    if (movieFileRefNum)
    {
        CloseMovieFile(movieFileRefNum);
    }
    
    if (theMovie)
    {
        DisposeMovie(theMovie);
    }

}

//////////
//
// getFrameCount
// 指定されたムービートラックのフレーム数を取得。
// エラーが発生した場合は、値 -1 を返し、
// トラックのフレーム数は特定できない
//
// 「Jr.c」の ConvertToMovie にあるフレームカウントに基づく
// (厳密ではない)
// 
// Interesting Time(トラックが新しいサンプルを表示する場所)
// のすべてを走査することにより、トラックのフレーム数をカウント
//
//////////

long getFrameCount (Track theTrack)
{   
    long        myCount = -1;
    short       myFlags;
    TimeValue   myTime = 0;
    
    if (theTrack == NULL)
        goto bail;
        
    // トラックの最初の フレーム(サンプル)から開始したい
    myFlags = nextTimeMediaSample + nextTimeEdgeOK;

    while (myTime >= 0) {
        myCount++;
        
    // トラック中の次フレームを探す。それ以上フレームがなければ
    // myTime に -1 が設定され、while ループを抜ける
        GetTrackNextInterestingTime(theTrack,
                                    myFlags,
                                    myTime,
                                    fixed1,
                                    &myTime,
                                    NULL);
        
    // 最初の Interesting Time 以降は、現在の Interesting Time を含めない
    //
        myFlags = nextTimeStep;
    }

bail:
    return(myCount);
}

//////////
//
// drawMovieFrameNextOrPrev
// QuickTime ムービーの直前または直後のビデオサンプルを描画
// theRate が 1 ならば、直後のビデオサンプルを描画
// theRate が -1 ならば、直前のビデオサンプルを描画
//
//////////

OSErr drawMovieFrameNextOrPrev (Movie theMovie, Fixed theRate)
{
    TimeValue       myCurrTime;
    TimeValue       myNextTime;
    short           myFlags;
    OSType          myTypes[1];
    OSErr           myErr = noErr;
    
    if (theMovie == NULL)
        return(invalidMovie);
    
    // ムービーのメディアの次のフレームを取得したい
    myFlags = nextTimeStep;
    // ビデオサンプルを取得したい
    myTypes[0] = VisualMediaCharacteristic;     
    myCurrTime = GetMovieTime(theMovie, NULL);

    GetMovieNextInterestingTime(theMovie,
                                myFlags,
                                1,
                                myTypes,
                                myCurrTime,
                                theRate,
                                &myNextTime,
                                NULL);
    myErr = GetMoviesError();
    if (myErr != noErr)
        return(myErr);
        
    myErr = drawMovieFrameAtTime(theMovie, myNextTime);
    
    return(myErr);
}

//////////
//
// drawMovieFrameAtTime
// 指定されたタイミングで QuickTime ムービーのビデオサンプルを描画
//
//////////

OSErr drawMovieFrameAtTime (Movie theMovie, TimeValue theTime)
{
    OSErr myErr = noErr;
    
    if (theMovie == NULL)
        return(invalidMovie);
    
    // 指定された時間が、ムービーの時間的境界の範囲内にあることを確認
    // 
    if ((theTime < 0) || (theTime > GetMovieDuration(theMovie)))
        return(paramErr);
    
    SetMovieTimeValue(theMovie, theTime);
    myErr = GetMoviesError();
    if (myErr != noErr)
        goto bail;
        
    // (イベントを MCIsPlayerEvent に渡し)メインイベントのループで
    // ムービーコントローライベントを処理する場合、以下の
    // MoviesTask への呼び出しは必要なく、実際、損害はない
    
    // MoviesTask を呼び出してすぐにムービーを再描画する
    MoviesTask(theMovie, 0L);
    myErr = GetMoviesError();

bail:
    return(myErr);
}



[2003 年 3 月 5 日]